package crud.dao.impl;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;

import common.utils.BeanUtil;

import crud.client.annotation.DisplayValue;
import crud.client.annotation.Email;
import crud.client.annotation.Label;
import crud.client.annotation.MultipleValue;
import crud.client.annotation.Parameter;
import crud.client.data.Colonne;
import crud.client.data.ColonneDataConverter;
import crud.client.data.ColonneString;
import crud.client.data.Table;
import crud.client.factory.form.FormItemFactory;
import crud.client.factory.list.grid.ListGridFieldFactory;
import crud.client.factory.validator.field.ValidatorFactory;
import crud.client.factory.validator.table.TableValidatorFactory;
import crud.dao.ColonneDAO;
import crud.server.util.DataConversionUtil;

public class ColonneDAOImpl implements ColonneDAO
{

	@Override
	public List<Colonne> loadAllByTable(Table table)
	{
		List<Colonne> colonneList = new ArrayList<Colonne>();
		
		// La classe représentant le mapping
		Class<?> mappingClass = BeanUtil.forName(table.getMappingClassName());
		
		// La liste des clefs primaires
		List<Field> fieldList = BeanUtil.getNonTransientFields(mappingClass);

		for (int cp = 0; cp <= fieldList.size() - 1; cp++)
		{
			Field field = fieldList.get(cp);

			Colonne colonne = DataConversionUtil.newColonne(field);
			Column columnAnnotation = field.getAnnotation(Column.class);
			Label labelAnnotation = field.getAnnotation(Label.class);
			DisplayValue displayAnnotation = field.getAnnotation(DisplayValue.class);
			Email emailAnnotation = field.getAnnotation(Email.class);
			GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
			crud.client.annotation.FormItemFactory formItemFactoryAnnotation = field.getAnnotation(crud.client.annotation.FormItemFactory.class);
			crud.client.annotation.ListGridFactory listGridFactoryAnnotation = field.getAnnotation(crud.client.annotation.ListGridFactory.class);
			crud.client.annotation.ColonneDataConverter colonneDataConverterAnnotation = field.getAnnotation(crud.client.annotation.ColonneDataConverter.class);
			crud.client.annotation.FieldValidatorFactoryList validatorFactoryListAnnotation = field.getAnnotation(crud.client.annotation.FieldValidatorFactoryList.class);
			crud.client.annotation.FieldValidatorFactory validatorFactoryAnnotation = field.getAnnotation(crud.client.annotation.FieldValidatorFactory.class);
			crud.client.annotation.TableValidatorFactoryList tableValidatorFactoryListAnnotation = field.getAnnotation(crud.client.annotation.TableValidatorFactoryList.class);
			crud.client.annotation.TableValidatorFactory tableValidatorFactoryAnnotation = field.getAnnotation(crud.client.annotation.TableValidatorFactory.class);
//			Range rangeAnnotation = field.getAnnotation(Range.class);

			// Affichage spécial 
			if (displayAnnotation != null)
			{
				colonne.setDisplayValue(displayAnnotation.expression());
			}
			
			// La taille ???
			if (columnAnnotation != null && columnAnnotation.length() > 0)
			{
				colonne.setTaille(columnAnnotation.length());
			}

			// Clef primaire ???
			colonne.setPk(BeanUtil.isIdField(field));

			// Generated Value ???
			if (generatedValue != null)
			{
				colonne.setGeneratedValue(true);
			}

			// Le nullable
			if (colonne.isPk() && generatedValue == null)
			{
				colonne.setNullable(true);
			}
			else if (columnAnnotation != null)
			{
				colonne.setNullable(columnAnnotation.nullable());
			}
			else
			{
				colonne.setNullable(false);
			}

			// L'index, la table, la property
			colonne.setIndex(cp);
			colonne.setTable(table);
			colonne.setProperty(field.getName());

			// Le code, le libellé
			colonne.setCodeColonne(field.getName());
			if (labelAnnotation != null)
			{
				colonne.setLibelle(labelAnnotation.value());
			} else if (columnAnnotation != null && columnAnnotation.name() != null)
			{
				colonne.setLibelle(columnAnnotation.name());
			} else
			{
				colonne.setLibelle(field.getName());
			}
			
			// Email ???
			if (emailAnnotation != null)
			{
				((ColonneString) colonne).setEmail(true);
			}
			
			// Range ???
//			if (rangeAnnotation != null)
//			{
//				if (rangeAnnotation.min() != null && rangeAnnotation.min().isEmpty() == false)
//				{
//					colonne.setMinValue(DataConversionUtil.donneeToString(colonne, donnee))
//				}
//				;
//			}
//		

			// Gestion des annotations spécifiques aux listes
			MultipleValue multipleValueAnnotation = field.getAnnotation(MultipleValue.class);
			if (multipleValueAnnotation != null)
			{
				FormItemFactory formItemFactory = (FormItemFactory) BeanUtil.newInstance(multipleValueAnnotation.factory());
				
				if (multipleValueAnnotation.values() != null && multipleValueAnnotation.values().length > 0)
				{
					BeanUtil.setProperty(formItemFactory, "values", multipleValueAnnotation.values());
				}
				colonne.setFormItemFactory(formItemFactory);
			}

			// FormItemFactory spécifique
			if (formItemFactoryAnnotation != null)
			{
				colonne.setFormItemFactory((FormItemFactory) BeanUtil.newInstance(formItemFactoryAnnotation.factory()));
			}

			// ListGridFactory spécifique
			if (listGridFactoryAnnotation != null)
			{
				colonne.setListGridFactory((ListGridFieldFactory) BeanUtil.newInstance(listGridFactoryAnnotation.factory()));
			}

			// ColonneDataConverter spécifique
			if (colonneDataConverterAnnotation != null)
			{
				colonne.setDataConverter((ColonneDataConverter) BeanUtil.newInstance(colonneDataConverterAnnotation.className()));
			}
			
			List<crud.client.annotation.FieldValidatorFactory> validatorFactoryList = new ArrayList<crud.client.annotation.FieldValidatorFactory>();
			
			// Un Validateur unique
			if (validatorFactoryAnnotation != null)
			{
				validatorFactoryList.add(validatorFactoryAnnotation);
			}
			
			// La validatorFactory
			if (validatorFactoryListAnnotation != null)
			{
				validatorFactoryList.addAll(Arrays.asList(validatorFactoryListAnnotation.validatorList()));
			}
			
			// Instanciation de validateurs
			for (crud.client.annotation.FieldValidatorFactory currentValidatorFactoryAnnotation : validatorFactoryList)
			{
				ValidatorFactory validatorFactory = (ValidatorFactory) BeanUtil.newInstance(currentValidatorFactoryAnnotation.factory().getName(), (Object[]) currentValidatorFactoryAnnotation.contructorArguments());
				
				for (Parameter parameter : currentValidatorFactoryAnnotation.parameterList())
				{
					BeanUtil.populateProperty(validatorFactory, parameter.name(), parameter.value());
				}
				colonne.addValidatorFactory(validatorFactory);
			}
				

			List<crud.client.annotation.TableValidatorFactory> tableValidatorFactoryList = new ArrayList<crud.client.annotation.TableValidatorFactory>();
			
			// Un Validateur unique
			if (tableValidatorFactoryAnnotation != null)
			{
				tableValidatorFactoryList.add(tableValidatorFactoryAnnotation);
			}

			// La validatorFactory
			if (tableValidatorFactoryListAnnotation != null)
			{
				tableValidatorFactoryList.addAll(Arrays.asList(tableValidatorFactoryListAnnotation.validatorList()));
			}
			
			// Instanciation de validateurs
			for (crud.client.annotation.TableValidatorFactory currentValidatorFactoryAnnotation : tableValidatorFactoryList)
			{
				TableValidatorFactory validatorFactory = (TableValidatorFactory) BeanUtil.newInstance(currentValidatorFactoryAnnotation.factory().getName(), (Object[]) currentValidatorFactoryAnnotation.contructorArguments());
				
				for (Parameter parameter : currentValidatorFactoryAnnotation.parameterList())
				{
					BeanUtil.populateProperty(validatorFactory, parameter.name(), parameter.value());
				}
				colonne.addTableValidatorFactory(validatorFactory);
			}

			colonneList.add(colonne);
		}

		
		return colonneList;
	}

}
